/*  Game/Army Editor for yALB - Yet Another List Builder (roster Editor for Wargames/tabletop games).
    Copyright (C) 2008-2012  Daniel Ricardo Castro Alvarado

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.*/
#include "unitoptions.h"
#include "ui_unitoptions.h"

#include "../other/functions.h"

#include <QDebug>

#ifndef UNIT_OPTION_INHERITED_KEY
#error This file depends on UNIT_OPTION_INHERITED_KEY
#endif

// \FIXME: Fix signals

UnitOptions::UnitOptions(ItemSelector &_itemSelector, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::UnitOptions), options()
{
    ui->setupUi(this);
    connectSignals();

    connect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
    connect(ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject()));

}

UnitOptions::~UnitOptions()
{
    delete ui;
}

void UnitOptions::clearOptionForm() {
    ui->actionBox->clearActionForm();
    ui->optState->setCurrentIndex(0);
    ui->optName->setText("");
    ui->optKey->setText("");
    ui->optRequired->setText("");
    ui->optCost->setValue(0.0);
    ui->optPointsPerMiniature->setChecked(false);

    ui->inheritOptionBox->setChecked(false);
    ui->inheritedOptionKey->setText("");
}

void UnitOptions::addCategory(const GameCategory &category, const QString &key) {
    QTreeWidgetItem *item = new QTreeWidgetItem(ui->optList, QStringList(category.getName()));
    item->setData(0, Qt::UserRole, key);
    ui->optCategory->addItem(category.getName(), key);

    QTreeWidgetItem *noCategory = ui->optList->topLevelItem(0);

    // Check if there are items with the new category key
    QTreeWidgetItem *child;
    for(int i = noCategory->childCount() -1; i>=0; --i) {
        child = noCategory->child(i);
        UnitOption option(options.get(child->data(0, Qt::UserRole).toString()));
        if(option.category == key) {
            noCategory->removeChild(child);
            item->addChild(child);
        }
    }
}

void UnitOptions::updateCategory(const QString &oldKey, const GameCategory &newCategory,
                                  const QString &newKey) {
    for(int i = 1; i<ui->optList->topLevelItemCount(); ++i) {
        QTreeWidgetItem *item = ui->optList->topLevelItem(i);
        if(item->data(0, Qt::UserRole).toString() == oldKey) {
            item->setText(0, newCategory.getName());
            ui->optCategory->setItemText(i, newCategory.getName());

            if(oldKey != newKey) {
                item->setData(0, Qt::UserRole, QVariant(newKey));
                ui->optCategory->setItemData(i, QVariant(newKey));

                int optionCount = item->childCount(); // Options in this category
                QTreeWidgetItem *noCategory = ui->optList->topLevelItem(0);

                // Move items in this category to "No category"
                Functions::moveChildrenToRow(item, noCategory);

                // Check if there are items with the new category key
                QTreeWidgetItem *child;
                for(int a = noCategory->childCount() - optionCount -1; a>=0; --a) {
                    child = noCategory->child(a);
                    UnitOption option(options.get(child->data(0, Qt::UserRole).toString()));
                    if(option.category == newKey) {
                        noCategory->removeChild(child);
                        item->addChild(child);
                    }
                }
            }
            break;
        }
    }
}

void UnitOptions::removeCategory(const QString &key) {
    for(int i = 1; i<ui->optList->topLevelItemCount(); ++i) {
        QTreeWidgetItem *item = ui->optList->topLevelItem(i);
        if(item->data(0, Qt::UserRole).toString() == key) {
            // Move items in this category to "No category"
            Functions::moveChildrenToRow(item, ui->optList->topLevelItem(0));
            delete item;
            ui->optCategory->removeItem(i);
            break;
        }
    }
}

void UnitOptions::clearAll() {
    qDeleteAll(ui->optList->topLevelItem(0)->takeChildren());
    for(int i = ui->optList->topLevelItemCount()-1; i>=1; --i) {
        qDeleteAll(ui->optList->topLevelItem(i)->takeChildren());
    }
    keyIndex.clear();
    clearOptionForm();
}

void UnitOptions::clearAllCategories() {
    for(int i = ui->optList->topLevelItemCount() -1; i>=1; --i) {
        Functions::moveChildrenToRow(ui->optList->topLevelItem(i), ui->optList->topLevelItem(0));
        delete ui->optList->topLevelItem(i);
        ui->optCategory->removeItem(i);
    }
}

void UnitOptions::clearAllProperties() {
    propertyForm.clearAll();
}

/*void UnitOptions::clearAllColumns() {
    ui->actionBox->clearAll();
}*/

OptionCollection UnitOptions::getUnitOptions(const OptionCollection& currentOptions) {
    fillFromUnitOptions(currentOptions);

    if(this->exec() == QDialog::Accepted) {
        return options;
    } else {
        return currentOptions;
    }
}

void UnitOptions::on_inheritOptionBox_stateChanged(int arg1)
{
    if(arg1 == Qt::Checked) {
        ui->inheritedOptionKey->setEnabled(true);
        ui->inheritedOptionLabel->setEnabled(true);
    } else {
        ui->inheritedOptionKey->setEnabled(false);
        ui->inheritedOptionLabel->setEnabled(false);
    }
}


void UnitOptions::on_optList_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous)
{
    Q_UNUSED(previous)
    propertyForm.clearAllValues();
    propertyForm.savePropertyValues();
    if(current->parent()) {
        QString key = current->data(0, Qt::UserRole).toString();
        if(options.contains(key)) {
            UnitOption option = options.get(key);

            int catIndex = ui->optCategory->findData(QVariant(option.category), Qt::UserRole);
            catIndex = catIndex > -1 && catIndex < ui->optCategory->count() ? catIndex : 0;

            if(!option.inheritedKey.isEmpty()) {
                ui->inheritedOptionKey->setText(option.inheritedKey);
                ui->inheritOptionBox->setChecked(true);
            } else {
                ui->inheritedOptionKey->setText("");
                ui->inheritOptionBox->setChecked(false);
            }
            ui->actionBox->setActions(option.actions);

            ui->optCategory->setCurrentIndex(catIndex);
            ui->optState->setCurrentIndex(int(option.state));
            ui->optName->setText(option.getName());
            ui->optKey->setText(key);
            ui->optRequired->setText(option.required);
            ui->optCost->setValue(option.getCost());
            ui->optPointsPerMiniature->setChecked(option.costPerMin);

            ui->optDelete->setEnabled(true);
            ui->optUpdate->setEnabled(true);
            ui->optClone->setEnabled(true);

            // Set up PropertyForm

            QHash<QString, QString>::const_iterator i;
            for(i = option.properties.constBegin();
                i != option.properties.constEnd(); ++i)
                propertyForm.setPropertyValue(i.key(), i.value());

            ui->optPropertiesBox->setEnabled(true);

        } else {
            qDebug() << "This ID does not exist in commonOptions";
            clearOptionForm();
            ui->optCategory->setCurrentIndex(ui->optList->indexOfTopLevelItem(current));
            ui->optDelete->setEnabled(false);
            ui->optUpdate->setEnabled(false);
            ui->optClone->setEnabled(false);

            ui->optPropertiesBox->setEnabled(false);
        }
    } else {
        clearOptionForm();
        ui->optCategory->setCurrentIndex(ui->optList->indexOfTopLevelItem(current));
        ui->optDelete->setEnabled(false);
        ui->optUpdate->setEnabled(false);
        ui->optClone->setEnabled(false);

        ui->optPropertiesBox->setEnabled(false);
    }
}

void UnitOptions::on_optAdd_clicked()
{
    UnitOption option(ui->optCategory->itemData(ui->optCategory->currentIndex(), Qt::UserRole).toString(),
                      GameStructs::getOptionStateFromInt(ui->optState->currentIndex()),
                      ui->optName->text(), (float)ui->optCost->value(), ui->optPointsPerMiniature->isChecked(),
                      ui->optRequired->text(), ui->actionBox->getActions(), QHash<QString, QString>());
    if(ui->inheritOptionBox->isChecked())
        option.inheritedKey = ui->inheritedOptionKey->text();

    options.add(option, ui->optKey->text());
}

void UnitOptions::on_optUpdate_clicked()
{
    if(ui->optList->currentItem()->parent()) {
        QString key = ui->optList->currentItem()->data(0, Qt::UserRole).toString();
        UnitOption currentOption = options.get(key);
        UnitOption option(ui->optCategory->itemData(ui->optCategory->currentIndex(), Qt::UserRole).toString(),
                          GameStructs::getOptionStateFromInt(ui->optState->currentIndex()),
                          ui->optName->text(), (float)ui->optCost->value(), ui->optPointsPerMiniature->isChecked(),
                          ui->optRequired->text(), ui->actionBox->getActions(), currentOption.properties);

        if(ui->inheritOptionBox->isChecked())
            option.inheritedKey = ui->inheritedOptionKey->text();

        options.update(key, option, ui->optKey->text());
    }
}

void UnitOptions::on_optDelete_clicked()
{
    QTreeWidgetItem* item = ui->optList->currentItem();
    if (item->parent()) {
        options.remove(item->data(0, Qt::UserRole).toString());
    }
}

void UnitOptions::on_optClone_clicked()
{
    QTreeWidgetItem* item = ui->optList->currentItem();
    if (item && item->parent()) {
        QString oldKey = item->data(0, Qt::UserRole).toString();
        QString newKey;
        const UnitOption &opt = options.get(oldKey);

        UnitOption option(opt);
        option.inheritedKey = opt.inheritedKey;

        int i = 0;

        bool valid = false;
        do {

            newKey = QString("%1_%2").arg(oldKey, QString::number(i));
            option.setName(QString("%1_%2").arg(opt.getName(), QString::number(i)));
            if(!GameStructs::isValidKey(newKey)) // Prevent the app to fall in an infinite loop
                break;
            valid = !options.contains(newKey);
            ++i;
        } while (valid == false);
        if(valid) {
            options.add(option, newKey);
        }
    }

}

void UnitOptions::on_optSetPropertiesButton_clicked()
{
    if(ui->optList->currentItem()) {
        QString key = ui->optList->currentItem()->data(0, Qt::UserRole).toString();
        if(!key.isEmpty() && propertyForm.exec() == QDialog::Accepted) {
            UnitOption option = options.get(key);
            option.properties = propertyForm.getProperties();
            options.update(key, option, key);
        }
    }
}

void UnitOptions::addOption(const UnitOption &option, const QString &key) {
    Q_ASSERT_X(!keyIndex.contains(key), "UnitOptions::addOption()", "Attempting to replace existing element");
    QTreeWidgetItem *item = new QTreeWidgetItem(QStringList(option.getName()));
    item->setData(0, Qt::UserRole, key);

    int index = 0; // Default to "No Category"
    if(!option.category.isEmpty()) {
        for(int i = 1; i<ui->optList->topLevelItemCount(); ++i) {
            if (ui->optList->topLevelItem(i)->data(0, Qt::UserRole).toString() == option.category) {
                index = i;
                break;
            }
        }
    }

    ui->optList->topLevelItem(index)->addChild(item);
    ui->optList->expandItem(ui->optList->topLevelItem(index));

    keyIndex.insert(key, item);

    clearOptionForm();
}

void UnitOptions::updateOption(const QString &oldKey, const UnitOption &newOption, const QString &newKey) {
    QTreeWidgetItem *item = keyIndex.value(oldKey, NULL);
    if(item) {
        if(oldKey != newKey) {
            item->setData(0, Qt::UserRole, QVariant(newKey));
            keyIndex.remove(oldKey);
            keyIndex.insert(newKey, item);
        }
        item->setText(0, newOption.getName());
        int indexOfParent = ui->optList->indexOfTopLevelItem(item->parent());
        int indexNewParent = 0;

        if (!newOption.category.isEmpty()) {
            for(int i = 1; i<ui->optList->topLevelItemCount(); ++i) {
                if (ui->optList->topLevelItem(i)->data(0, Qt::UserRole).toString() == newOption.category) {
                    indexNewParent = i;
                    break;
                }
            }
        }

        if (indexOfParent != indexNewParent) {
            ui->optList->topLevelItem(indexOfParent)->removeChild(item);
            ui->optList->topLevelItem(indexNewParent)->addChild(item);
            ui->optList->expandItem(item->parent());
            ui->optList->setCurrentItem(item);
        }
    }
}

void UnitOptions::removeOption(const QString &key) {
    QTreeWidgetItem *item = keyIndex.value(key, NULL);
    if(item) {
        delete item;
        keyIndex.remove(key);
    }
}

void UnitOptions::connectSignals() {
    connect(&options, SIGNAL(optionAdded(UnitOption,QString)), this,
            SLOT(addOption(UnitOption,QString)));
    connect(&options, SIGNAL(optionUpdated(QString,UnitOption,QString)),
            this, SLOT(updateOption(QString,UnitOption,QString)));
    connect(&options, SIGNAL(optionRemoved(QString)), this, SLOT(removeOption(QString)));
}

void UnitOptions::disconnectSignals() {
    disconnect(&options, SIGNAL(optionAdded(UnitOption,QString)), this,
            SLOT(addOption(UnitOption,QString)));
    disconnect(&options, SIGNAL(optionUpdated(QString,UnitOption,QString)),
            this, SLOT(updateOption(QString,UnitOption,QString)));
    disconnect(&options, SIGNAL(optionRemoved(QString)), this, SLOT(removeOption(QString)));
}

void UnitOptions::removeAllFromUI() {
    keyIndex.clear();
    for(int i = 0; i<ui->optList->topLevelItemCount(); ++i)
        qDeleteAll(ui->optList->topLevelItem(i)->takeChildren());
    clearOptionForm();
}

void UnitOptions::fillFromUnitOptions(const OptionCollection &currentOptions) {
    removeAllFromUI();

    disconnectSignals();
    options = currentOptions;
    connectSignals();

    QStringList keys = options.keys();
    for(int i = 0; i<keys.count(); ++i)
        addOption(options.get(keys.at(i)), keys.at(i));
}

void UnitOptions::changeEvent(QEvent *event) {
    if(event->type() == QEvent::LanguageChange)
        ui->retranslateUi(this);
    QWidget::changeEvent(event);
}
